package tablemanager;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;

import main.Application;
import sqladapter.SQLAdapter;
import sqladapter.SQLFieldAttributes;
import browser.filter.BrowserFilter;
import exception.queryBuilder.AliasNotFound;
import exception.queryBuilder.AttribNotFound;
import exception.queryBuilder.UndefineKeyType;


/**
 * 
 * @author looser
 *
 */ 
 
public class TableManager 
{
	String tableName;
	Map<String,SQLFieldAttributes> fields;
	Map<String,SQLFieldAttributes> keys;
	SQLQueryBuilder queryBuilder;
	
	public TableManager(SQLAdapter adapter)
	{		 
		fields = adapter.getFields();
		keys = adapter.getKeys();
		tableName= adapter.getTableName();
		queryBuilder = new SQLQueryBuilder(fields,tableName,adapter);
	}
	
	/**
	 * 
	 * @return zwraca dane,ktore maja byc wyswietlone w browserze
	 * @throws SQLException 
	 * @throws SQLException
	 */
	public ResultSet getDataTable(BrowserFilter filter) throws SQLException
	{	
		return getDataTable(filter,-666);
	}
		
	
	public ResultSet getDataTable(int limitNumber) throws SQLException
	{	
		return getDataTable(null,limitNumber);
	}
	
	private ResultSet getDataTable(BrowserFilter filter,int limitNumber) throws SQLException
	{
		ResultSet result=null;
		Statement stmt;
		
		stmt = Application.getInstance().getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
		String query;
		if(limitNumber>=0)
			query = queryBuilder.getSelectVisibleQuery(limitNumber);
		else
			query = queryBuilder.getSelectVisibleQuery(filter);		 
		
		Application.getInstance().getLogger().info(query);
		result = stmt.executeQuery(query);		
		return result;
	}
	
	public void deleteRecord(Map<String,String> keyVals) throws AttribNotFound, UndefineKeyType, SQLException 
	{		
		String query= queryBuilder.getDeleteQuery(keyVals);			
		executeQuery(query);
	}
	/**
	 * 
	 * @param record <br>
	 * 		<b>nazwa pola</b>	- nazwa jak w bazie <br>
	 * 		<b>wartosc</b>		- nazwa jak w bazie
	 * @throws UndefineKeyType 
	 * @throws SQLException 
	 * @throws Exception 
	 */
	public void dadajRecord(Map<String,String> record) throws UndefineKeyType, SQLException 
	{				
		String q=queryBuilder.getInsertQuery(record);
		executeQuery(q);
	}
	
	/**
	 * 
	 * @param record <br>
	 * 		<i><b>nazwa pola</b>	- nazwa jak w bazie</i> <br>
	 * 		<i><b>wartosc</b>		- wartosc </i><br>
	 * @param keyVals <br> 	
	 * 				- wartosci klucza dla recordu, ktory ma byc modyfikowany <br>
	 * 				< alias klucza, wartosc klucza >
	 * @throws AttribNotFound 
	 * @throws UndefineKeyType 
	 * @throws SQLException 
	 * 							
	 * @throws Exception 
	 */
	public void modyfikujRecord(Map<String,String> record,Map<String,String> keyVals) throws UndefineKeyType, AttribNotFound, SQLException
	{			
		String q=queryBuilder.getModyfiQuery(validRecord(record), keyVals);
		executeQuery(q);
	}	
	/**
	 * jezeli ktos przekaze record z widoku, to funkcja usunie z niego atrybuty nie nalezace do tabeli, ktorej dotyczy modyfikacja
	 * @param record
	 * @return
	 */
	private Map<String,String> validRecord(Map<String,String> record)
	{
		Map<String,String> newRec = new HashMap<String, String>();
		String[] keys = record.keySet().toArray(new String[0]);
		for(int i=0;i<keys.length;++i)
		{
			if(fields.get(keys[i])!=null)
			{
				newRec.put(keys[i], record.get(keys[i]));
			}				
		}
		return newRec;
	}
	/**
	 * wykona zapodane zapytanie
	 * @param query
	 * @throws SQLException 
	 */
	private void executeQuery(String query) throws SQLException
	{
		Connection con = Application.getInstance().getConnection();;			 
		Statement stmt = con.createStatement();	
		Application.getInstance().getLogger().info(query);
		stmt.execute(query);
	}
	
	/**
	 * 
	 * @return zwraca liste aliasow atrybutow kluczowych
	 */
	public String[] getKeys()
	{
		Object [] keysArr= keys.keySet().toArray();
		int keysAmmount = keysArr.length;
		String[] keyAlliases = new String[keysAmmount];
		for (int i=0;i<keysAmmount;++i)
		{
			keyAlliases[i]= keys.get(keysArr[i]).getFieldAllias();
		}
		return keyAlliases;
	}
	
	/**
	 * 
	 * @return zwraca liste nazw jak w bazie atrybutow kluczowych
	 */
	public String[] getKeysNames()
	{
		Object [] keysArr= keys.keySet().toArray();
		int keysAmmount = keysArr.length;
		String[] keyAlliases = new String[keysAmmount];
		for (int i=0;i<keysAmmount;++i)
		{
			keyAlliases[i]= keys.get(keysArr[i]).getFieldName();
		}
		return keyAlliases;
	}
	
	/**
	 * 
	 * @param keys < allias , wartosc >
	 * @return  < nazwa jak w bazie,wartosc >
	 * @throws UndefineKeyType 
	 * @throws AttribNotFound 
	 * @throws SQLException 
	 * @throws Exception 
	 */
	public Map<String,String> getRecord(Map<String,String> keys) throws AttribNotFound, UndefineKeyType, SQLException
	{
		String query = queryBuilder.getSelectFromKeys(keys);
		
		ResultSet result;				
		Statement stmt = Application.getInstance().getConnection().createStatement();			
		result = stmt.executeQuery(query);		
		
		HashMap<String,String> record = new HashMap<String, String>();
		
		if(!result.next())
			return null;
		
		java.sql.ResultSetMetaData resultMD = result.getMetaData();
		int length =resultMD.getColumnCount();
		for(int i=1;i<=length;++i)
		{
			record.put(queryBuilder.getFieldNameFromAlias(resultMD.getColumnName(i)), result.getString(i));
		}
		return record;
	}
	/**
	 * podaje sie nazwe pola jak w bazie i zwraca alias jak w xmlu
	 * @param fieldName
	 * @return
	 * @throws AliasNotFound 
	 * @throws Exception 
	 */
	public String getAlias(String fieldName) throws AliasNotFound
	{
		return queryBuilder.getAliasFromFieldName(fieldName);
	}
	/**
	 * metoda sprawdzi,czy zapodane pole jest w tabeli/widoku
	 * @param fiedlName nazwa jak w bazie
	 * @return
	 */
	public boolean validField(String fieldName)
	{
		return queryBuilder.validField(fieldName);
	}
}
